{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "04b2e8a8-edd3-488f-aa53-178975c70d4f",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "from langchain.agents import create_structured_chat_agent, AgentExecutor\n",
    "from langchain.memory import ConversationBufferMemory\n",
    "from langchain.schema import HumanMessage\n",
    "from langchain.tools import BaseTool\n",
    "from langchain_openai import ChatOpenAI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ff01c0a8-56db-41ad-b6ae-0223694dfa37",
   "metadata": {},
   "outputs": [],
   "source": [
    "model = ChatOpenAI(model='gpt-3.5-turbo', temperature=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "37a1ce53-4fee-4714-8601-29105922c11a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='这句话一共有16个字。', response_metadata={'token_usage': {'completion_tokens': 11, 'prompt_tokens': 42, 'total_tokens': 53}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_c2295e73ad', 'finish_reason': 'stop', 'logprobs': None}, id='run-067a889a-6dfc-4730-91c5-e783f1a18311-0')"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.invoke([HumanMessage(content=\"'君不见黄河之水天上来奔流到海不复回'，这句话的字数是多少？\")])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "61e0a761-aaed-4459-8e1a-d44237e5df94",
   "metadata": {},
   "outputs": [],
   "source": [
    "class TextLengthTool(BaseTool):\n",
    "    name = \"文本字数计算工具\"\n",
    "    description = \"当你被要求计算文本的字数时，使用此工具\"\n",
    "\n",
    "    def _run(self, text):\n",
    "        return len(text)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "a4b27e9d-b7e3-475d-86ae-3e09389153e2",
   "metadata": {},
   "outputs": [],
   "source": [
    "tools = [TextLengthTool()]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "bdc51694-3e5b-4359-af7b-e512f8fb8b18",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ChatPromptTemplate(input_variables=['agent_scratchpad', 'input', 'tool_names', 'tools'], input_types={'chat_history': typing.List[typing.Union[langchain_core.messages.ai.AIMessage, langchain_core.messages.human.HumanMessage, langchain_core.messages.chat.ChatMessage, langchain_core.messages.system.SystemMessage, langchain_core.messages.function.FunctionMessage, langchain_core.messages.tool.ToolMessage]]}, messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=['tool_names', 'tools'], template='Respond to the human as helpfully and accurately as possible. You have access to the following tools:\\n\\n{tools}\\n\\nUse a json blob to specify a tool by providing an action key (tool name) and an action_input key (tool input).\\n\\nValid \"action\" values: \"Final Answer\" or {tool_names}\\n\\nProvide only ONE action per $JSON_BLOB, as shown:\\n\\n```\\n{{\\n  \"action\": $TOOL_NAME,\\n  \"action_input\": $INPUT\\n}}\\n```\\n\\nFollow this format:\\n\\nQuestion: input question to answer\\nThought: consider previous and subsequent steps\\nAction:\\n```\\n$JSON_BLOB\\n```\\nObservation: action result\\n... (repeat Thought/Action/Observation N times)\\nThought: I know what to respond\\nAction:\\n```\\n{{\\n  \"action\": \"Final Answer\",\\n  \"action_input\": \"Final response to human\"\\n}}\\n\\nBegin! Reminder to ALWAYS respond with a valid json blob of a single action. Use tools if necessary. Respond directly if appropriate. Format is Action:```$JSON_BLOB```then Observation')), MessagesPlaceholder(variable_name='chat_history', optional=True), HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['agent_scratchpad', 'input'], template='{input}\\n\\n{agent_scratchpad}\\n (reminder to respond in a JSON blob no matter what)'))])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prompt = hub.pull(\"hwchase17/structured-chat-agent\")\n",
    "prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "a3505348-19a4-4556-b6bb-f383a220856f",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent = create_structured_chat_agent(\n",
    "    llm=model,\n",
    "    tools=tools,\n",
    "    prompt=prompt\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "8bee8104-c62a-44f7-939e-65fb634b8411",
   "metadata": {},
   "outputs": [],
   "source": [
    "memory = ConversationBufferMemory(\n",
    "        memory_key='chat_history',\n",
    "        return_messages=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "3068bab6-ae7a-4e9a-8ac0-2916a17b227a",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent_executor = AgentExecutor.from_agent_and_tools(\n",
    "    agent=agent, tools=tools, memory=memory, verbose=True, handle_parsing_errors=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "0c88f942-0061-4d24-b075-dc3f33f4fc04",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m{\n",
      "  \"action\": \"文本字数计算工具\",\n",
      "  \"action_input\": {\n",
      "    \"text\": \"君不见黄河之水天上来奔流到海不复回\"\n",
      "  }\n",
      "}\u001b[0m\u001b[36;1m\u001b[1;3m17\u001b[0m\u001b[32;1m\u001b[1;3m{\n",
      "  \"action\": \"Final Answer\",\n",
      "  \"action_input\": \"这句话的字数是17\"\n",
      "}\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'input': \"'君不见黄河之水天上来奔流到海不复回'，这句话的字数是多少？\",\n",
       " 'chat_history': [HumanMessage(content=\"'君不见黄河之水天上来奔流到海不复回'，这句话的字数是多少？\"),\n",
       "  AIMessage(content='这句话的字数是17')],\n",
       " 'output': '这句话的字数是17'}"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor.invoke({\"input\": \"'君不见黄河之水天上来奔流到海不复回'，这句话的字数是多少？\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "5d77973d-8e92-4614-93b7-d14646f43437",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m{\n",
      "  \"action\": \"Final Answer\",\n",
      "  \"action_input\": \"量子力学是研究微观世界中原子和亚原子粒子行为的物理学分支。它描述了微观粒子的运动和相互作用，涉及概率性和波粒二象性等概念。\"\n",
      "}\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'input': '请你充当我的物理老师，告诉我什么是量子力学',\n",
       " 'chat_history': [HumanMessage(content=\"'君不见黄河之水天上来奔流到海不复回'，这句话的字数是多少？\"),\n",
       "  AIMessage(content='这句话的字数是17'),\n",
       "  HumanMessage(content='请你充当我的物理老师，告诉我什么是量子力学'),\n",
       "  AIMessage(content='量子力学是研究微观世界中原子和亚原子粒子行为的物理学分支。它描述了微观粒子的运动和相互作用，涉及概率性和波粒二象性等概念。')],\n",
       " 'output': '量子力学是研究微观世界中原子和亚原子粒子行为的物理学分支。它描述了微观粒子的运动和相互作用，涉及概率性和波粒二象性等概念。'}"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor.invoke({\"input\": \"请你充当我的物理老师，告诉我什么是量子力学\"})"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
